/**
 * Title: jFamilyTree provider
 * Description: jFamilyTree Provider
 * Version: provider
 * Copyright: (c) 2001-2008
 * Terms of use:see license agreement at http://treebolic.sourceforge.net/en/license.htm
 * Author: Bernard Bou
 * Company: bsys
 * Update: Mon Mar 10 00:00:00 CEST 2008
 */

package jFamilyTree.provider.xml.fast;

import java.net.URL;

import javax.swing.JOptionPane;

import jFamilyTree.model.Tree;
import jFamilyTree.model.IProvider;
import jFamilyTree.model.IProviderContext;
import jFamilyTree.model.Model;

/**
 * Provider factory implementation
 * 
 * @author Bernard Bou
 */
public class Provider implements IProvider
{
	// D A T A

	/**
	 * Context used to query for Url
	 */
	private IProviderContext theContext;

	/**
	 * Url
	 */
	protected URL theUrl;

	// CO N S T R U C T O R

	/**
	 * Constructor
	 */
	public Provider()
	{
		theUrl = null;
	}

	// M A K E

	/*
	 * (non-Javadoc)
	 * 
	 * @see jFamilyTree.model.IProvider#set(jFamilyTree.model.IProviderContext)
	 */
	public void connect(IProviderContext thisContext)
	{
		theContext = thisContext;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see jFamilyTree.model.IProvider#makeModel(java.lang.String)
	 */
	public Model makeModel(String thisSource)
	{
		URL thisUrl = makeUrl(thisSource);
		if (thisUrl == null)
			return null;

		theUrl = thisUrl;
		theContext.putProgress("Loading ..." + thisUrl.toString(), false);
		Model thisModel = parseModel(thisUrl);
		theContext.putProgress("Loaded " + thisUrl.toString(), false);
		return thisModel;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see jFamilyTree.model.IProvider#makeTree(java.lang.String, boolean)
	 */
	public Tree makeTree(String thisSource, boolean checkRecursion)
	{
		URL thisUrl = makeUrl(thisSource);
		if (thisUrl == null)
			return null;

		// direct recursion prevention
		if (checkRecursion && thisUrl.equals(theUrl))
		{
			theContext.putMessage("Recursion: " + thisUrl.toString());
			return null;
		}

		theUrl = thisUrl;
		theContext.putProgress("Loading ..." + thisUrl.toString(), false);
		Tree thisTree = parseTree(thisUrl);
		theContext.putProgress("Loaded " + thisUrl.toString(), false);
		return thisTree;
	}

	/**
	 * Make Url
	 * 
	 * @param thisSource
	 *        source
	 * @return URL
	 */
	private URL makeUrl(String thisSource)
	{
		while (true)
		{
			// process
			URL thisUrl = theContext.makeURL(thisSource);
			if (thisUrl != null)
				return thisUrl;

			// ask
			thisSource = ask("Source: " + thisSource + "\nEnter data URL:\n");
			if (thisSource == null || thisSource.isEmpty())
			{
				// give up
				inform("Source is null.\nAborting.");
				return null;
			}
		}
	}

	// P A R S E

	/**
	 * Populate model with data from URL
	 * 
	 * @param thisURL
	 *        url
	 * @return model or null
	 */
	private Model parseModel(URL thisURL)
	{
		// parse
		// assumes URL is valid
		Parser thisParser = new Parser(thisURL, this);
		if (thisParser.isValid())
			return thisParser.parseModel();
		return null;
	}

	/**
	 * Populate tree with data from URL
	 * 
	 * @param thisURL
	 *        url
	 * @return tree or null
	 */
	private Tree parseTree(URL thisURL)
	{
		// parse
		// assumes URL is valid
		Parser thisParser = new Parser(thisURL, this);
		if (thisParser.isValid())
			return thisParser.parseTree();
		return null;
	}

	/**
	 * Ask dialog
	 * 
	 * @param thisMessage
	 *        message
	 * @return input
	 */
	private String ask(String thisMessage)
	{
		String[] theseLines = thisMessage.split("\n");
		return JOptionPane.showInputDialog(null, theseLines);
	}

	/**
	 * Inform dialog
	 * 
	 * @param thisMessage
	 *        message
	 */
	private void inform(String thisMessage)
	{
		String[] theseLines = thisMessage.split("\n");
		JOptionPane.showMessageDialog(null, theseLines, "jFamilyTree XML provider", JOptionPane.WARNING_MESSAGE);
	}
}
